/* 实现Promise.all、race、allSettled、finally */
function isPromise(val) {
  if (typeof val == 'object' && val != null || typeof val == "function") {
    if (typeof val.then == "function") { return true }
  }
  return false;
}


Promise.prototype.finally = function (fn) {
  return this.then(data => {
    return Promise.resolve(fn()).then(() => data)
  }, err => {
    return Promise.resolve(fn()).then(() => {
      throw err
    })
  })
}


Promise.resolve = function (val) {
  if (isPromise(val)) {
    return val
  }
  return new Promise((resolve) => { resolve(val) });
}


Promise.reject = function (val) {


  return new Promise((resolve, reject) => { reject(val) });
}


Promise.all = function (list) {
  return new Promise((resolve, reject) => {
    if (list.length == 0) { return resolve() }
    let results = [], total = 0;


    function handle(i, val) {
      total++;
      results[i] = val;
      if (total == list.length) {
        resolve(results);
      }
    }


    for (let [i, item] of list.entries()) {
      if (isPromise(item)) {
        item.then(res => {
          handle(i, res);
        }, reject);
      } else {
        handle(i, item);
      }
    }


  });
}
Promise.allSettled = function (list) {
  return new Promise((resolve, reject) => {
    if (list.length == 0) { return resolve() }
    let results = [], total = 0;


    function handle(i, val) {
      total++;
      results[i] = val;
      if (total == list.length) {
        resolve(results);
      }
    }
    for (let [i, item] of list.entries()) {
      if (isPromise(item)) {
        item.then(res => {
          handle(i, res);
        }, err => {
          handle(i, err);
        });
      } else {
        handle(i, item);
      }
    }
  });
}
Promise.race = function (list) {
  return new Promise((resolve, reject) => {
    if (list.length == 0) { resolve() }


    for (let [i, item] of list.entries()) {
      if (isPromise(item)) {
        item.then(res => {
          resolve(item);
          return
        }, reject);
      } else {
        resolve(item);
        return
      }
    }
  });
}


const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 5000));
const promises = [promise2, promise1];


Promise.allSettled(promises).
  then((results) => {
    console.log("allsettled");
    console.log(results);
  });